#include "GLScene.h"
#include "MeshOp.h"
#include "ObjReader.h"
#include "STPReader.h"
#include "LSCMBuilder.h"
#include "ARAPBuilder.h"
#include "ParaBuilder.h"

#include "Test.h"

void loader()
{
	GLProgram* program = GLProgram::ShareProgram();
	GLScene* scene = program->ShareScene();

	ObjReader objR;
	STPReader stpR;

	{
		TColgp_SequenceOfPnt points;

		TIMER_START(GEN);
		int M = testSixArcBoundary(points);
		int N = points.Size();
		TIMER_END(GEN);

		int Nu = 16, Nv = 16;
		std::vector<double> u(N), v(N);
		std::vector<double> w(N, 1);

		TIMER_START(BUILD);
		Para::ParaBuilder builder(points);
		builder.Build(u, v, Nu, Nv, 3, 3, w);
		TIMER_END(BUILD);

	}


	// 载入顶点和纹理数据
	// -----------------------------------------------------------------
	/*
	scene->AddTexture("../../data/color.png", USER_TEXTURE_ID);

	TIMER_START(READ_OBJ);
	MeshPtr mesh = objR.ReadMesh("../../data/bunny.obj", true);
	TIMER_END(READ_OBJ);

	std::cout << "Vertices: " << mesh->n_vertices() << std::endl;

	std::function<Mesh::Point(double u, double v)> f = [](double u, double v) -> Mesh::Point
		{
			const double PI = 3.1415926;
			double x = u;
			double y = 0.1 * sin(5 * PI * u) * cos(3 * PI * v) + 1.0;
			double z = v;

			return Mesh::Point(x, y, z);
		};

	// 指定生成器
	std::function<int(TColgp_SequenceOfPnt&)> generator = [&](TColgp_SequenceOfPnt& points) -> int
		{
			return testSixArcBoundary(points);
		};

	TIMER_START(GENERATE);
	auto mesh2 = MeshOp::GenerateRandomMesh(100, 1, f);
	//MeshPtr mesh2 = MeshOp::ReadMesh("../../data/bunny.obj", true);
	//MeshPtr mesh2 = MeshOp::GenerateTrimmedMesh(100, trimSurf);
	TIMER_END(GENERATE);

	std::cout << "Vertices: " << mesh2->n_vertices() << std::endl;

	TIMER_START(LSCM);
	LSCM::SODFeatureMetric metric(15);
	LSCM::LSCMBuilder lscmBuilder(mesh2.get(), &metric);
	auto charts = lscmBuilder.Build();
	TIMER_END(LSCM);

	TIMER_START(ARAP);
	ARAP::ARAPBuilder arapBuilder(mesh2.get(), charts, 1e-16);
	arapBuilder.Build(3);
	TIMER_END(ARAP);

	TIMER_START(TO_GLMESH);
	GLMeshPtr mesh2Ptr = objR.AsGLMesh(mesh2);
	scene->AddMesh(mesh2Ptr, GL_FILL);
	mesh2Ptr->SetDiffuseTex(TEXTURE::CHESS);
	TIMER_END(TO_GLMESH);

	GLMeshPtr paramesh2Ptr = objR.AsParaGLMesh(mesh2);
	scene->AddMesh(paramesh2Ptr, GL_LINE);
	paramesh2Ptr->SetDiffuseTex(TEXTURE::YELLOW);

	std::cout << "Finish" << std::endl;

	// ---------------------------------------------------
	// GLCurve
	//GLCurvePtr curve(new GLCurve({ {0.0, 0.0, 0.0}, {1.0, 1.0, 1.0} }));
	//scene->AddCurve(curve);

	auto reader = stpR.ReadSTP("../../data/example1.stp");
	auto& curves = stpR.ReadCurve(reader);
	for (auto c : curves)
		scene->AddCurve(stpR.AsGLCurve(c));

	auto& surf = stpR.ReadSurface(reader);
	for (auto f : surf)
		scene->AddMesh(stpR.AsGLMesh(f), GL_FILL);

	for (int i = 1; i <= reader.NbShapes(); i++)
	{
		auto& shape = reader.Shape(i);
		std::cout << "Shape" << std::endl;
		TopExp_Explorer Ex;
		for (Ex.Init(shape, TopAbs_EDGE); Ex.More(); Ex.Next())
			std::cout << "Edge" << std::endl;

		for (Ex.Init(shape, TopAbs_FACE); Ex.More(); Ex.Next())
			std::cout << "Face" << std::endl;

		for (Ex.Init(shape, TopAbs_WIRE); Ex.More(); Ex.Next())
		{
			std::cout << "Wire" << std::endl;
		}
	}
	*/
}

// 绘制顶点数据
void painter()
{
	GLProgram* program = GLProgram::ShareProgram();

	glEnable(GL_DEPTH_TEST);
	glClearColor(0.2f, 0.2f, 0.2f, 0.2f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// 绘制环境
	program->ShareScene()->Draw();
}

int main()
{
	int flag = 0;
	GLProgram* program = GLProgram::CreateProgram(800, 800, "LearnOpenGL", flag);

	// 如果初始化失败就退出
	if (flag == -1)
		return -1;

	// 开启消息循环
	program->MessageLoop(loader, painter);
	program->DeleteProgram();

	return 0;
}